package com.opennetexam.manager.utils;

import org.springframework.beans.factory.annotation.Value;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;

/**
 * Created by 奶茶 on 2017/9/25.
 */
public class EncrptUtil {


    /**
     * Encode md 5 hex string.
     *
     * @param str the str
     * @return the string
     * @throws Exception the exception
     */
//将字符串加密成MD5，32位16进制字串，如"3031209"转成"e043a49740adde7aae4f34818c52528e"
    public static String encodeMD5Hex(String str) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(str.getBytes("UTF-8"));
        byte[] result = md.digest();
        StringBuffer sb = new StringBuffer(32);
        for (int i = 0; i < result.length; i++) {
            int val = result[i] & 0xff;
            if (val < 0xf) {
                sb.append("0");
            }
            sb.append(Integer.toHexString(val));
        }
        return sb.toString().toLowerCase();
    }

    private static String md5(String input) {
        if ((input == null) || (input.length() == 0)) {
            return "D41D8CD98F00B204E9800998ECF8427E";     //这个值是为了兼容C语言的DLL MD5值而存在
        } else {
            StringBuffer sb = new StringBuffer();
            try {
                MessageDigest algorithm = MessageDigest.getInstance("MD5");
                algorithm.reset();
                algorithm.update(input.getBytes());
                byte[] md5 = algorithm.digest();
                String singleByteHex = "";
                for (int i = 0; i < md5.length; i++) {
                    singleByteHex = Integer.toHexString(0xFF & md5[i]);
                    if (singleByteHex.length() == 1) {
                        sb.append("0");
                    }
                    sb.append(singleByteHex.toUpperCase());
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return sb.toString();
        }
    }

    /**
     * Md 5 encryption string.
     *
     * @param plainText the plain text
     * @return the string
     */
    public static String md5Encryption(String plainText) {
        String reMd5 = new String();
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(plainText.getBytes());
            byte[] b = md.digest();

            int i;

            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0) {
                    i += 256;
                }
                if (i < 16) {
                    buf.append("0");
                }
                buf.append(Integer.toHexString(i));
            }

            reMd5 = buf.toString();

        } catch (Exception e) {
            e.printStackTrace();
        }
        return reMd5;
    }

    /**
     * Decrypt do net string.
     *
     * @param message the message
     * @param key     the key
     * @return the string
     * @throws Exception the exception
     */
    public static String decryptDoNet(String message, String key) throws Exception {
        //base64 + des 解密.net 加密传来串
        //byte[] bytesrc = convertHexString(message); //不用base64 的方式
        BASE64Decoder base64Decoder = new BASE64Decoder();
        byte[] bytesrc = base64Decoder.decodeBuffer(message);
        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        //Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
        IvParameterSpec iv = new IvParameterSpec(key.getBytes("UTF-8"));
        cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
        byte[] retByte = cipher.doFinal(bytesrc);

        return new String(retByte);
    }

    /**
     * 计划包解密
     * @param message
     * @param key
     * @return
     */
    public static String examPlanPagkageDESDecrypt(String message, String key) throws Exception {
        return decryptDoNet(message, key);
    }

    /**
     * Encrypt as do net string.
     *
     * @param message the message
     * @param key     the key
     * @return the string
     * @throws Exception the exception
     */
    public static String encryptAsDoNet(String message, String key) throws Exception {
        //产生与.net 对应的加密des + base64 加密串
        //message = java.net.URLEncoder.encode(message, "ascii");
        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        //Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
        IvParameterSpec iv = new IvParameterSpec(key.getBytes("UTF-8"));
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
        byte[] encryptbyte = cipher.doFinal(message.getBytes());
        BASE64Encoder base64Encoder = new BASE64Encoder();
        //base64Encoder.encode(encryptbyte);
        return base64Encoder.encode(encryptbyte).replaceAll("\r\n", "").replaceAll("\n", "");
//        toHexString(encryptbyte).toUpperCase();
    }

    public static String aesEncryptAsDoNet(String message, String key) throws Exception {
        //产生与.net 对应的加密des + base64 加密串
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
        //IvParameterSpec iv = new IvParameterSpec(key.getBytes("UTF-8"));
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encryptbyte = cipher.doFinal(message.getBytes());
        BASE64Encoder base64Encoder = new BASE64Encoder();
        //base64Encoder.encode(encryptbyte);
        return base64Encoder.encode(encryptbyte).replaceAll("\r\n", "").replaceAll("\n", "");
    }

    /**
     * 考试计划包解密
     * @param decryptString 需要解密字符串
     * @return
     */
    public static String examPlanPagkageDESDecrypt(String decryptString) throws Exception {
        return decryptDoNet(decryptString,"OPEN@)!#");
    }

    public static void main(String[] args) throws Exception {
        String message = "{\"planId\":66,\"planName\":\"BS机考随到随考测试（正式）\"}";
        String str = "yKnZ+++sZwg=";
        String open2003 = encryptAsDoNet(message, "open2003");
        String open20031 = decryptDoNet(str, "OPEN@)!#");
        System.out.println(open2003);
        System.out.println(open20031);
    }
}
